package com.hd.trans.camerax;

import android.animation.ArgbEvaluator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.view.animation.LinearInterpolator;

import com.hd.trans.utils.DisplayUtils;

import java.util.ArrayList;
import java.util.List;

public class ScanMaskDrawable extends Drawable {

    private final Context mContext;
    private List<Point> mCropPoints;
    private List<Point> renderPoints;
    private final Paint mLinePaint;
    private final Paint mMaskPaint;

    private final Path mPointLinePath = new Path();
    private boolean mShowMask;

    private float mScaleX = 1f;
    private float mScaleY = 1f;

    public ScanMaskDrawable(Context context) {
        mContext = context;

        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLinePaint.setColor(0xFF3A88F9);
        mLinePaint.setStrokeWidth(DisplayUtils.dp2px(mContext,2));
        mLinePaint.setStyle(Paint.Style.STROKE);

        mMaskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mMaskPaint.setColor(0x554CAF50);
        mMaskPaint.setStyle(Paint.Style.FILL);
    }

    public void setLineColor(int lineColor) {
        mLinePaint.setColor(lineColor);
        invalidateSelf();
    }

    public void setLineWidth(int lineWidthDp) {
        mLinePaint.setStrokeWidth(DisplayUtils.dp2px(mContext,lineWidthDp));
        invalidateSelf();
    }

    public void setMaskColor(int maskColor) {
        this.mMaskPaint.setColor(maskColor);
        invalidateSelf();
    }

    public void showMask(boolean showMask) {
        this.mShowMask = showMask;
        invalidateSelf();
    }

    ValueAnimator valueAnimator;

    public void onDestroy() {
        if (valueAnimator != null) {
            valueAnimator.cancel();
        }
    }

    public void setCropPoints(List<Point> cropPoints, boolean useAnimator, float scaleX,float scaleY) {
        this.mScaleX = scaleX;
        this.mScaleY = scaleY;
        if (!useAnimator) {
            this.mCropPoints = this.renderPoints = cropPoints;
            invalidateSelf();
            return;
        }

        if (valueAnimator != null) {
            valueAnimator.cancel();
        }
        if (this.renderPoints == null) {
            this.renderPoints = cropPoints;
            invalidateSelf();
        } else {
            valueAnimator = ValueAnimator.ofObject(new PointsEvaluator(), this.renderPoints, cropPoints);
            valueAnimator.setInterpolator(new LinearInterpolator());
            valueAnimator.setDuration(150);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    renderPoints = (List<Point>) valueAnimator.getAnimatedValue();
                    invalidateSelf();
                }
            });
            valueAnimator.start();
        }
        this.mCropPoints = cropPoints;
    }

    private boolean checkPoints(List<Point> points) {
        return points != null && points.size() == 4
                && points.get(0) != null && points.get(1) != null && points.get(2) != null && points.get(3) != null;
    }

    private Path resetPointPath() {
        if (!checkPoints(renderPoints)) {
            return null;
        }
        mPointLinePath.reset();
        Point lt = renderPoints.get(0);
        Point rt = renderPoints.get(1);
        Point rb = renderPoints.get(2);
        Point lb = renderPoints.get(3);
        mPointLinePath.moveTo(lt.x * mScaleX, lt.y * mScaleY);
        mPointLinePath.lineTo(rt.x * mScaleX, rt.y * mScaleY);
        mPointLinePath.lineTo(rb.x * mScaleX, rb.y * mScaleY);
        mPointLinePath.lineTo(lb.x * mScaleX, lb.y * mScaleY);
        mPointLinePath.close();

        ValueAnimator.ofObject(new ArgbEvaluator(), 1, 2).start();

        return mPointLinePath;
    }

    @Override
    public int getIntrinsicHeight() {
        return getBounds().bottom - getBounds().top;
    }

    @Override
    public int getIntrinsicWidth() {
        return getBounds().right - getBounds().left;
    }

    @Override
    public void draw(Canvas canvas) {
        int saveCount = canvas.save();
        Path path = resetPointPath();
        if (path != null) {
            if (mShowMask) {
                canvas.drawPath(path, mMaskPaint);
            }
            canvas.drawPath(path, mLinePaint);
        }
        canvas.restoreToCount(saveCount);
    }

    @Override
    public void setAlpha(int i) {
        mLinePaint.setAlpha(i);
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        mLinePaint.setColorFilter(colorFilter);
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    static class PointsEvaluator implements TypeEvaluator<List<Point>> {

        private final ArrayList<Point> resultList = new ArrayList<>();

        {
            for (int i = 0; i < 4; i++) {
                resultList.add(new Point());
            }
        }

        @Override
        public List<Point> evaluate(float fraction, List<Point> startValue, List<Point> endValue) {
            for (int i = 0; i < startValue.size(); i++) {
                createPoint(fraction, startValue.get(i), endValue.get(i), resultList.get(i));
            }
            return resultList;
        }

        private void createPoint(float fraction, Point startValue, Point endValue, Point result) {
            result.x = (int) (startValue.x + (endValue.x - startValue.x) * fraction);
            result.y = (int) (startValue.y + (endValue.y - startValue.y) * fraction);
        }
    }

}
